#!/bin/bash
###############################################################################
#       脚本名称: env.sh
#       功能描述: ENV文件操作模块，提供.env文件的读取、写入、删除、环境变量管理等功能。
#       作者: 林再来
#       日期: 2025-10-14
#       版本: 1.2
#       功能:
#           1、ENV文件读取、写入、删除操作
#           2、ENV文件格式验证
#           3、ENV文件加载到环境变量
#           4、从环境变量导出到ENV文件
#           5、ENV文件变更检测和监控
#           6、ENV文件备份和恢复功能
#       依赖(插件/命令):
#           1、grep
#           2、sed
#           3、md5sum或cksum
###############################################################################

# 防止重复加载
if [[ -n "${env_sh_loaded:-}" ]]; then
    return 0
fi
readonly env_sh_loaded=1

# 注意：不使用严格模式，避免影响交互式 shell

# 获取脚本目录和项目根目录（如果尚未定义）
if [[ -z "${script_dir:-}" ]]; then
    script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    readonly script_dir
fi

if [[ -z "${project_root:-}" ]]; then
    project_root="$(cd "${script_dir}/../.." && pwd)"
    readonly project_root
fi

###############################################################################
# 基础操作函数
###############################################################################

# 函数: 验证ENV文件格式
# 参数: $1 - ENV文件路径
# 返回: 0-格式正确, 1-格式错误
function env_validate() {
    local env_file="$1"
    
    if [[ -z "$env_file" ]]; then
        log_error "env" "错误: 缺少参数: ENV文件路径"
        return 1
    fi
    
    if [[ ! -f "$env_file" ]]; then
        log_error "env" "错误: ENV文件不存在: $env_file"
        return 1
    fi
    
    log_debug "env" "验证ENV文件格式: $env_file"
    
    # ENV文件格式比较宽松，主要检查语法错误
    # 逐行检查是否符合 KEY=VALUE 格式
    local line_num=0
    local has_error=false
    
    while IFS= read -r line; do
        ((line_num++))
        
        # 跳过空行
        [[ -z "$line" ]] && continue
        
        # 跳过注释行（#开头）
        [[ "$line" =~ ^[[:space:]]*# ]] && continue
        
        # 去除export前缀进行检查
        local check_line="$line"
        check_line="${check_line#export }"
        check_line="${check_line#export	}"
        
        # 检查格式: KEY=VALUE
        # KEY必须以字母或下划线开头，后面可以是字母、数字、下划线
        if [[ ! "$check_line" =~ ^[A-Za-z_][A-Za-z0-9_]*= ]]; then
            log_warn "env" "第${line_num}行格式可能有误: $line"
            has_error=true
        fi
    done < "$env_file"
    
    if [[ "$has_error" == "true" ]]; then
        log_warn "env" "ENV文件包含格式警告，但不影响解析"
    fi
    
    log_debug "env" "ENV文件格式验证完成: $env_file"
    return 0
}

# 函数: 读取ENV文件中的值
# 参数: $1 - ENV文件路径, $2 - 键名称
# 返回: 0-成功, 1-失败
function env_read() {
    local env_file="$1"
    local key="$2"
    
    if [[ -z "$env_file" ]] || [[ -z "$key" ]]; then
        log_error "env" "错误: 缺少参数: ENV文件路径和键"
        return 1
    fi
    
    if [[ ! -f "$env_file" ]]; then
        log_error "env" "错误: ENV文件不存在: $env_file"
        return 1
    fi
    
    log_debug "env" "读取ENV值: $env_file -> $key"
    
    # 使用grep查找匹配的行
    # 支持: KEY=VALUE, export KEY=VALUE
    local value
    value=$(grep -E "^(export[[:space:]]+)?${key}=" "$env_file" 2>/dev/null | \
            head -1 | \
            sed -e 's/^export[[:space:]]*//' \
                -e "s/^${key}=//" \
                -e 's/^"//' -e 's/"$//' \
                -e "s/^'//" -e "s/'$//")
    
    # 返回值（可能为空）
    echo "$value"
    return 0
}

# 函数: 写入值到ENV文件
# 参数: $1 - ENV文件路径, $2 - 键名称, $3 - 值, $4 - 是否使用export(可选)
# 返回: 0-成功, 1-失败
function env_write() {
    local env_file="$1"
    local key="$2"
    local value="$3"
    local use_export="${4:-false}"
    
    if [[ -z "$env_file" ]] || [[ -z "$key" ]]; then
        log_error "env" "错误: 缺少参数: ENV文件路径和键"
        return 1
    fi
    
    # 如果文件不存在，创建
    if [[ ! -f "$env_file" ]]; then
        log_info "env" "ENV文件不存在，创建新文件: $env_file"
        touch "$env_file" || {
            log_error "env" "错误: 无法创建ENV文件: $env_file"
            return 1
        }
    fi
    
    log_debug "env" "写入ENV值: $env_file -> $key = $value"
    
    # 备份原文件
    local backup_file="${env_file}.bak.$(date +%s)"
    cp "$env_file" "$backup_file" || {
        log_error "env" "错误: 无法创建备份文件: $backup_file"
        return 1
    }
    
    # 处理特殊字符（包含空格、$、`、\等需要加引号）
    local quoted_value="$value"
    if [[ "$value" =~ [[:space:]] ]] || [[ "$value" =~ [\$\`\\] ]] || [[ "$value" =~ [\"\'#] ]]; then
        # 需要加引号，同时转义内部的引号和反斜杠
        quoted_value=$(echo "$value" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g')
        quoted_value="\"$quoted_value\""
    fi
    
    # 构建新行
    local new_line
    if [[ "$use_export" == "true" ]]; then
        new_line="export ${key}=${quoted_value}"
    else
        new_line="${key}=${quoted_value}"
    fi
    
    # 检查键是否存在
    if grep -qE "^(export[[:space:]]+)?${key}=" "$env_file"; then
        # 存在：替换该行
        # 使用临时文件避免sed -i的平台兼容性问题
        sed -E "s|^(export[[:space:]]+)?${key}=.*|${new_line}|" "$env_file" > "${env_file}.tmp"
        mv "${env_file}.tmp" "$env_file"
    else
        # 不存在：追加新行
        echo "$new_line" >> "$env_file"
    fi
    
    # 验证修改
    if env_validate "$env_file"; then
        rm -f "$backup_file"
        log_debug "env" "ENV值写入成功"
        return 0
    else
        log_error "env" "错误: 写入后ENV文件格式错误，恢复备份"
        mv "$backup_file" "$env_file"
        return 1
    fi
}

# 函数: 删除ENV文件中的键
# 参数: $1 - ENV文件路径, $2 - 键名称
# 返回: 0-成功, 1-失败
function env_delete() {
    local env_file="$1"
    local key="$2"
    
    if [[ -z "$env_file" ]] || [[ -z "$key" ]]; then
        log_error "env" "错误: 缺少参数: ENV文件路径和键"
        return 1
    fi
    
    if [[ ! -f "$env_file" ]]; then
        log_error "env" "错误: ENV文件不存在: $env_file"
        return 1
    fi
    
    log_debug "env" "删除ENV键: $env_file -> $key"
    
    # 备份原文件
    local backup_file="${env_file}.bak.$(date +%s)"
    cp "$env_file" "$backup_file" || {
        log_error "env" "错误: 无法创建备份文件: $backup_file"
        return 1
    }
    
    # 删除匹配的行
    sed -E "/^(export[[:space:]]+)?${key}=/d" "$env_file" > "${env_file}.tmp"
    mv "${env_file}.tmp" "$env_file"
    
    # 验证修改
    if env_validate "$env_file"; then
        rm -f "$backup_file"
        log_debug "env" "ENV键删除成功"
        return 0
    else
        log_error "env" "错误: 删除后ENV文件格式错误，恢复备份"
        mv "$backup_file" "$env_file"
        return 1
    fi
}

# 函数: 列出ENV文件中的所有键
# 参数: $1 - ENV文件路径
# 返回: 0-成功, 1-失败
function env_list_keys() {
    local env_file="$1"
    
    if [[ -z "$env_file" ]]; then
        log_error "env" "错误: 缺少参数: ENV文件路径"
        return 1
    fi
    
    if [[ ! -f "$env_file" ]]; then
        log_error "env" "错误: ENV文件不存在: $env_file"
        return 1
    fi
    
    log_debug "env" "列出ENV键: $env_file"
    
    # 提取所有键名
    grep -E '^(export[[:space:]]+)?[A-Za-z_][A-Za-z0-9_]*=' "$env_file" 2>/dev/null | \
    sed -E 's/^export[[:space:]]+//' | \
    cut -d'=' -f1 | \
    sort -u
    
    return 0
}

###############################################################################
# 环境变量操作函数
###############################################################################

# 函数: 加载ENV文件到环境变量
# 参数: $1 - ENV文件路径
# 返回: 0-成功, 1-失败
function env_load_to_environment() {
    local env_file="$1"
    
    if [[ -z "$env_file" ]]; then
        log_error "env" "错误: 缺少参数: ENV文件路径"
        return 1
    fi
    
    if [[ ! -f "$env_file" ]]; then
        log_error "env" "错误: ENV文件不存在: $env_file"
        return 1
    fi
    
    log_info "env" "加载ENV文件到环境: $env_file"
    
    local loaded_count=0
    
    # 逐行读取并导出
    while IFS= read -r line; do
        # 跳过空行
        [[ -z "$line" ]] && continue
        
        # 跳过注释行
        [[ "$line" =~ ^[[:space:]]*# ]] && continue
        
        # 去除export前缀
        line="${line#export }"
        line="${line#export	}"
        
        # 验证是否是有效的环境变量格式
        if [[ "$line" =~ ^[A-Za-z_][A-Za-z0-9_]*= ]]; then
            # 导出到环境变量（使用 || true 防止 set -e 导致脚本退出）
            if export "$line" 2>/dev/null; then
                ((loaded_count++))
            else
                log_warn "env" "无法导出环境变量: ${line%%=*}"
            fi
        fi
    done < "$env_file"
    
    log_info "env" "成功加载 $loaded_count 个环境变量"
    return 0
}

# 函数: 从环境变量导出到ENV文件
# 参数: $1 - ENV文件路径, $@ - 要导出的键名列表
# 返回: 0-成功, 1-失败
function env_export_from_environment() {
    local env_file="$1"
    shift
    local keys=("$@")
    
    if [[ -z "$env_file" ]]; then
        log_error "env" "错误: 缺少参数: ENV文件路径"
        return 1
    fi
    
    if [[ ${#keys[@]} -eq 0 ]]; then
        log_error "env" "错误: 至少需要指定一个要导出的环境变量"
        return 1
    fi
    
    log_info "env" "从环境变量导出到ENV文件: $env_file"
    
    # 如果文件不存在，创建
    if [[ ! -f "$env_file" ]]; then
        touch "$env_file" || {
            log_error "env" "错误: 无法创建ENV文件: $env_file"
            return 1
        }
    fi
    
    local exported_count=0
    
    # 遍历指定的环境变量
    for key in "${keys[@]}"; do
        # 检查环境变量是否存在
        if [[ -v "$key" ]]; then
            local value="${!key}"
            if env_write "$env_file" "$key" "$value" "true"; then
                ((exported_count++))
                log_debug "env" "导出环境变量: $key"
            else
                log_warn "env" "导出环境变量失败: $key"
            fi
        else
            log_warn "env" "环境变量不存在: $key"
        fi
    done
    
    log_info "env" "成功导出 $exported_count 个环境变量"
    return 0
}

###############################################################################
# 文件操作函数
###############################################################################

# 函数: 合并ENV文件
# 参数: $1 - 目标文件, $2 - 源文件, $3 - 合并模式(可选: merge/overwrite)
# 返回: 0-成功, 1-失败
function env_merge() {
    local target_file="$1"
    local source_file="$2"
    local merge_mode="${3:-merge}"
    
    if [[ -z "$target_file" ]] || [[ -z "$source_file" ]]; then
        log_error "env" "错误: 缺少参数: 目标文件和源文件路径"
        return 1
    fi
    
    if [[ ! -f "$source_file" ]]; then
        log_error "env" "错误: 源文件不存在: $source_file"
        return 1
    fi
    
    # 如果目标文件不存在，直接复制源文件
    if [[ ! -f "$target_file" ]]; then
        log_info "env" "目标文件不存在，复制源文件: $target_file"
        cp "$source_file" "$target_file"
        return $?
    fi
    
    log_debug "env" "合并ENV文件: $source_file -> $target_file (模式: $merge_mode)"
    
    # 备份目标文件
    local backup_file="${target_file}.bak.$(date +%s)"
    cp "$target_file" "$backup_file" || {
        log_error "env" "错误: 无法创建备份文件: $backup_file"
        return 1
    }
    
    # 根据合并模式处理
    case "$merge_mode" in
        "overwrite")
            # 覆盖模式：源文件的值覆盖目标文件
            # 读取源文件的所有键值对
            while IFS= read -r line; do
                # 跳过空行和注释
                [[ -z "$line" ]] && continue
                [[ "$line" =~ ^[[:space:]]*# ]] && continue
                
                # 提取键和值
                local clean_line="${line#export }"
                clean_line="${clean_line#export	}"
                
                if [[ "$clean_line" =~ ^([A-Za-z_][A-Za-z0-9_]*)=(.*)$ ]]; then
                    local key="${BASH_REMATCH[1]}"
                    local value="${BASH_REMATCH[2]}"
                    
                    # 去除引号
                    value="${value#\"}"
                    value="${value%\"}"
                    value="${value#\'}"
                    value="${value%\'}"
                    
                    # 判断原行是否有export
                    local use_export="false"
                    if [[ "$line" =~ ^export[[:space:]]+ ]]; then
                        use_export="true"
                    fi
                    
                    # 写入目标文件
                    env_write "$target_file" "$key" "$value" "$use_export" || {
                        log_error "env" "合并失败，恢复备份"
                        mv "$backup_file" "$target_file"
                        return 1
                    }
                fi
            done < "$source_file"
            ;;
        "merge"|*)
            # 合并模式：只添加目标文件中不存在的键
            while IFS= read -r line; do
                # 跳过空行和注释
                [[ -z "$line" ]] && continue
                [[ "$line" =~ ^[[:space:]]*# ]] && continue
                
                # 提取键
                local clean_line="${line#export }"
                clean_line="${clean_line#export	}"
                
                if [[ "$clean_line" =~ ^([A-Za-z_][A-Za-z0-9_]*)=(.*)$ ]]; then
                    local key="${BASH_REMATCH[1]}"
                    
                    # 检查目标文件中是否已存在该键
                    if ! grep -qE "^(export[[:space:]]+)?${key}=" "$target_file"; then
                        # 不存在，追加整行到目标文件
                        echo "$line" >> "$target_file"
                    fi
                fi
            done < "$source_file"
            ;;
    esac
    
    # 验证结果
    if env_validate "$target_file"; then
        rm -f "$backup_file"
        log_debug "env" "ENV文件合并成功"
        return 0
    else
        log_error "env" "错误: 合并后ENV文件格式错误，恢复备份"
        mv "$backup_file" "$target_file"
        return 1
    fi
}

# 函数: 格式化ENV文件
# 参数: $1 - ENV文件路径
# 返回: 0-成功, 1-失败
function env_format() {
    local env_file="$1"
    
    if [[ -z "$env_file" ]]; then
        log_error "env" "错误: 缺少参数: ENV文件路径"
        return 1
    fi
    
    if [[ ! -f "$env_file" ]]; then
        log_error "env" "错误: ENV文件不存在: $env_file"
        return 1
    fi
    
    log_debug "env" "格式化ENV文件: $env_file"
    
    # 备份原文件
    local backup_file="${env_file}.bak.$(date +%s)"
    cp "$env_file" "$backup_file" || {
        log_error "env" "错误: 无法创建备份文件: $backup_file"
        return 1
    }
    
    # 格式化处理：
    # 1. 移除行尾空格
    # 2. 统一空行（多个空行合并为一个）
    # 3. 文件末尾确保有一个换行符
    sed -e 's/[[:space:]]*$//' \
        -e '/^$/N;/^\n$/D' \
        "$env_file" > "${env_file}.tmp"
    
    # 确保文件末尾有换行符
    if [[ -s "${env_file}.tmp" ]]; then
        # 检查最后一个字符是否是换行符
        if [[ "$(tail -c1 "${env_file}.tmp")" != "" ]]; then
            echo "" >> "${env_file}.tmp"
        fi
    fi
    
    mv "${env_file}.tmp" "$env_file"
    
    # 验证结果
    if env_validate "$env_file"; then
        rm -f "$backup_file"
        log_debug "env" "ENV文件格式化成功"
        return 0
    else
        log_error "env" "错误: 格式化后ENV文件格式错误，恢复备份"
        mv "$backup_file" "$env_file"
        return 1
    fi
}

###############################################################################
# 变更检测函数
###############################################################################

# 函数: 计算ENV文件哈希值
# 参数: $1 - ENV文件路径, $@ - 要计算哈希的键数组(可选)
# 返回: 哈希值字符串
function env_get_hash() {
    local env_file="$1"
    shift
    local keys=("$@")
    
    if [[ -z "$env_file" ]]; then
        log_error "env" "错误: 缺少参数: ENV文件路径"
        return 1
    fi
    
    if [[ ! -f "$env_file" ]]; then
        log_error "env" "错误: ENV文件不存在: $env_file"
        return 1
    fi
    
    log_debug "env" "计算ENV文件哈希值: $env_file"
    
    local content=""
    
    if [[ ${#keys[@]} -eq 0 ]]; then
        # 如果没有指定键，计算整个文件的内容哈希（排除注释和空行）
        content=$(grep -E '^(export[[:space:]]+)?[A-Za-z_][A-Za-z0-9_]*=' "$env_file" 2>/dev/null | sort)
    else
        # 计算指定键的值的哈希
        for key in "${keys[@]}"; do
            local value
            value=$(env_read "$env_file" "$key")
            content="${content}${key}=${value}"
        done
    fi
    
    # 计算哈希值(三级降级策略)
    if command -v md5sum >/dev/null 2>&1; then
        echo -n "$content" | md5sum | cut -d' ' -f1
    elif command -v cksum >/dev/null 2>&1; then
        echo -n "$content" | cksum | cut -d' ' -f1
    else
        # 简单的字符串长度和首尾字符作为备用哈希
        local first_char=""
        local last_char=""
        if [[ -n "$content" ]]; then
            first_char=$(echo -n "$content" | head -c1)
            last_char=$(echo -n "$content" | tail -c1)
        fi
        echo -n "${#content}-${first_char}-${last_char}"
    fi
}

# 函数: 保存ENV文件哈希值到文件
# 参数: $1 - ENV文件路径, $2 - 哈希文件路径(可选), $@ - 要保存哈希的键数组(可选)
# 返回: 0-成功, 1-失败
function env_save_hash() {
    local env_file="$1"
    local hash_file="${2:-}"
    shift 2
    local keys=("$@")
    
    if [[ -z "$env_file" ]]; then
        log_error "env" "错误: 缺少参数: ENV文件路径"
        return 1
    fi
    
    # 如果没有指定哈希文件，使用默认路径
    if [[ -z "$hash_file" ]]; then
        hash_file="${env_file}.hash"
    fi
    
    log_debug "env" "保存ENV哈希值: $env_file -> $hash_file"
    
    # 计算哈希值
    local hash_value
    if [[ ${#keys[@]} -eq 0 ]]; then
        hash_value=$(env_get_hash "$env_file")
    else
        hash_value=$(env_get_hash "$env_file" "${keys[@]}")
    fi
    
    if [[ $? -ne 0 ]] || [[ -z "$hash_value" ]]; then
        log_error "env" "错误: 计算哈希值失败"
        return 1
    fi
    
    # 保存哈希值到文件
    if echo "$hash_value" > "$hash_file"; then
        log_debug "env" "哈希值已保存: $hash_value"
        return 0
    else
        log_error "env" "错误: 保存哈希值失败: $hash_file"
        return 1
    fi
}

# 函数: 检查ENV文件是否发生变更
# 参数: $1 - ENV文件路径, $2 - 哈希文件路径(可选), $@ - 要检查的键数组(可选)
# 返回: 0-发生变更, 1-未发生变更
function env_check_changed() {
    local env_file="$1"
    local hash_file="${2:-}"
    shift 2
    local keys=("$@")
    
    if [[ -z "$env_file" ]]; then
        log_error "env" "错误: 缺少参数: ENV文件路径"
        return 1
    fi
    
    if [[ ! -f "$env_file" ]]; then
        log_error "env" "错误: ENV文件不存在: $env_file"
        return 1
    fi
    
    # 如果没有指定哈希文件，使用默认路径
    if [[ -z "$hash_file" ]]; then
        hash_file="${env_file}.hash"
    fi
    
    log_debug "env" "检查ENV文件变更: $env_file"
    
    # 如果哈希文件不存在，说明是第一次检查，视为已变更
    if [[ ! -f "$hash_file" ]]; then
        log_debug "env" "哈希文件不存在，视为已变更: $hash_file"
        return 0
    fi
    
    # 读取保存的哈希值
    local saved_hash
    saved_hash=$(cat "$hash_file" 2>/dev/null | head -1)
    if [[ -z "$saved_hash" ]]; then
        log_debug "env" "无法读取保存的哈希值，视为已变更"
        return 0
    fi
    
    # 计算当前哈希值
    local current_hash
    if [[ ${#keys[@]} -eq 0 ]]; then
        current_hash=$(env_get_hash "$env_file")
    else
        current_hash=$(env_get_hash "$env_file" "${keys[@]}")
    fi
    
    if [[ $? -ne 0 ]] || [[ -z "$current_hash" ]]; then
        log_error "env" "错误: 计算当前哈希值失败"
        return 1
    fi
    
    # 比较哈希值
    if [[ "$current_hash" != "$saved_hash" ]]; then
        log_debug "env" "检测到配置变更 (当前: $current_hash, 保存: $saved_hash)"
        return 0
    else
        log_debug "env" "配置未发生变更"
        return 1
    fi
}

###############################################################################
# 帮助函数
###############################################################################

# 函数: 显示帮助信息
function env_help() {
    cat << 'EOF'
ENV文件操作工具 (env.sh) - 使用说明

功能函数：
  env_validate <env_file>           - 验证ENV文件格式
  env_read <env_file> <key>         - 读取ENV值
  env_write <env_file> <key> <value> [export] - 写入ENV值
  env_delete <env_file> <key>       - 删除ENV键
  env_list_keys <env_file>          - 列出所有键
  env_merge <target> <source> [mode] - 合并ENV文件
  env_format <env_file>             - 格式化ENV文件

环境变量操作：
  env_load_to_environment <env_file>        - 加载ENV文件到环境变量
  env_export_from_environment <env_file> <keys...> - 从环境变量导出到ENV文件

变更检测函数：
  env_get_hash <env_file> [keys...]           - 计算ENV文件哈希值
  env_save_hash <env_file> [hash_file] [keys...] - 保存哈希值到文件
  env_check_changed <env_file> [hash_file] [keys...] - 检查是否变更

参数说明：
  env_file   - ENV文件路径
  key        - 键名称（必须以字母或下划线开头）
  value      - 要设置的值
  export     - 是否使用export关键字（true/false，默认false）
  keys       - 键数组，多个键用空格分隔
  mode       - 合并模式：merge(默认，仅添加新键)|overwrite(覆盖已存在的键)
  hash_file  - 哈希文件路径

ENV文件格式：
  KEY=VALUE              # 基本格式
  export KEY=VALUE       # 使用export
  KEY="VALUE"            # 带引号的值
  KEY='VALUE'            # 单引号值
  # 注释行              # 注释
  
  注意事项：
  - 键名必须以字母或下划线开头
  - 键名只能包含字母、数字、下划线
  - 值如果包含空格、特殊字符，会自动加引号

使用示例：
  # 基本操作
  env_read app.env "DB_HOST"
  env_write app.env "DB_PORT" "3306"
  env_delete app.env "OLD_KEY"
  
  # 列出所有键
  env_list_keys app.env
  
  # 环境变量操作
  env_load_to_environment app.env
  env_export_from_environment app.env "PATH" "HOME" "USER"
  
  # 合并ENV文件
  env_merge prod.env dev.env "merge"
  
  # 变更检测
  env_get_hash app.env "DB_HOST" "DB_PORT"
  env_save_hash app.env app.hash
  env_check_changed app.env app.hash

EOF
}

###############################################################################
# 简单日志函数（如果外部日志模块不可用）
###############################################################################

if ! command -v log_debug >/dev/null 2>&1; then
    function log_debug() {
        local module="${1:-}"
        shift
        echo "[DEBUG] [$module] $*" >&2
    }
fi

if ! command -v log_info >/dev/null 2>&1; then
    function log_info() {
        local module="${1:-}"
        shift
        echo "[INFO]  [$module] $*" >&2
    }
fi

if ! command -v log_warn >/dev/null 2>&1; then
    function log_warn() {
        local module="${1:-}"
        shift
        echo "[WARN]  [$module] $*" >&2
    }
fi

if ! command -v log_error >/dev/null 2>&1; then
    function log_error() {
        local module="${1:-}"
        shift
        echo "[ERROR] [$module] $*" >&2
    }
fi

